using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BanZuiCloudControlAgent.Core.Tasks.Enums;
using BanZuiCloudControlAgent.Utils.Logging;

namespace BanZuiCloudControlAgent.Core.Tasks.Utils
{
    /// <summary>
    /// 任务互斥管理器，用于控制任务的互斥执行
    /// </summary>
    public class TaskMutexManager
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly Logger _logger;
        
        /// <summary>
        /// 任务组信号量字典，每个任务组对应一个信号量
        /// </summary>
        private readonly Dictionary<TaskGroup, SemaphoreSlim> _groupSemaphores;
        
        /// <summary>
        /// 当前正在执行的任务组
        /// </summary>
        private readonly Dictionary<TaskGroup, int> _runningTasksCount;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        public TaskMutexManager()
        {
            _logger = LogManager.GetLogger(typeof(TaskMutexManager).Name);
            _groupSemaphores = new Dictionary<TaskGroup, SemaphoreSlim>();
            _runningTasksCount = new Dictionary<TaskGroup, int>();
            
            // 初始化各任务组的信号量
            foreach (TaskGroup group in Enum.GetValues(typeof(TaskGroup)))
            {
                // 交互类和采集类任务组的信号量初始值为1，表示同时只能有一个任务执行
                // 系统类和默认组的信号量初始值较大，允许多个任务并行执行
                int initialCount = (group == TaskGroup.Interactive || group == TaskGroup.Collection) ? 1 : 10;
                _groupSemaphores[group] = new SemaphoreSlim(initialCount, initialCount);
                _runningTasksCount[group] = 0;
            }
        }
        
        /// <summary>
        /// 尝试获取任务组的执行锁
        /// </summary>
        /// <param name="group">任务组</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>如果成功获取锁，则返回true；否则返回false</returns>
        public async Task<bool> TryAcquireGroupLockAsync(TaskGroup group, int timeout = 0, CancellationToken cancellationToken = default)
        {
            if (!_groupSemaphores.TryGetValue(group, out SemaphoreSlim semaphore))
            {
                _logger.Error($"未找到任务组 {group} 的信号量");
                return false;
            }
            
            try
            {
                bool acquired;
                
                if (timeout > 0)
                {
                    acquired = await semaphore.WaitAsync(timeout, cancellationToken);
                }
                else
                {
                    await semaphore.WaitAsync(cancellationToken);
                    acquired = true;
                }
                
                if (acquired)
                {
                    lock (_runningTasksCount)
                    {
                        _runningTasksCount[group]++;
                    }
                    
                    _logger.Debug($"成功获取任务组 {group} 的执行锁，当前运行任务数: {_runningTasksCount[group]}");
                }
                else
                {
                    _logger.Debug($"获取任务组 {group} 的执行锁超时");
                }
                
                return acquired;
            }
            catch (OperationCanceledException)
            {
                _logger.Debug($"获取任务组 {group} 的执行锁被取消");
                return false;
            }
            catch (Exception ex)
            {
                _logger.Error($"获取任务组 {group} 的执行锁时发生异常: {ex.Message}", ex);
                return false;
            }
        }
        
        /// <summary>
        /// 释放任务组的执行锁
        /// </summary>
        /// <param name="group">任务组</param>
        public void ReleaseGroupLock(TaskGroup group)
        {
            if (!_groupSemaphores.TryGetValue(group, out SemaphoreSlim semaphore))
            {
                _logger.Error($"未找到任务组 {group} 的信号量");
                return;
            }
            
            try
            {
                lock (_runningTasksCount)
                {
                    if (_runningTasksCount[group] > 0)
                    {
                        _runningTasksCount[group]--;
                    }
                }
                
                semaphore.Release();
                _logger.Debug($"释放任务组 {group} 的执行锁，当前运行任务数: {_runningTasksCount[group]}");
            }
            catch (Exception ex)
            {
                _logger.Error($"释放任务组 {group} 的执行锁时发生异常: {ex.Message}", ex);
            }
        }
        
        /// <summary>
        /// 获取任务组当前运行的任务数
        /// </summary>
        /// <param name="group">任务组</param>
        /// <returns>任务数</returns>
        public int GetRunningTasksCount(TaskGroup group)
        {
            lock (_runningTasksCount)
            {
                return _runningTasksCount.TryGetValue(group, out int count) ? count : 0;
            }
        }
        
        /// <summary>
        /// 判断任务组是否有可用的执行槽位
        /// </summary>
        /// <param name="group">任务组</param>
        /// <returns>如果有可用槽位，则返回true；否则返回false</returns>
        public bool HasAvailableSlot(TaskGroup group)
        {
            if (!_groupSemaphores.TryGetValue(group, out SemaphoreSlim semaphore))
            {
                return false;
            }
            
            return semaphore.CurrentCount > 0;
        }
    }
} 